home *** CD-ROM | disk | FTP | other *** search
/ Internet Info 1994 March / Internet Info CD-ROM (Walnut Creek) (March 1994).iso / networking / cisco / gdpd19jan91.shar / irdpd.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-08-07  |  22.2 KB  |  976 lines

  1. /*
  2.  * Router Discovery Protocol daemon suitable for using on Un*x systems.
  3.  *
  4.  * September 1989, Greg Satz
  5.  *
  6.  * Copyright (c) 1989 by cisco Systems, Inc.
  7.  * All rights reserved.
  8.  */
  9.  
  10. #include <sys/types.h>
  11. #include <sys/socket.h>
  12. #include <sys/ioctl.h>
  13. #include <sys/file.h>
  14. #include <sys/mbuf.h>
  15. #ifdef    sun
  16. #include <sys/limits.h>
  17. #else
  18. #define    INT_MAX 0x7ffffff    /* assume 32 bit ints */
  19. #endif
  20.  
  21. #include <net/if.h>
  22. #include <net/route.h>
  23. #include <netinet/in.h>
  24. #ifndef pyr
  25. #include <netinet/if_ether.h>
  26. #else
  27. #include <net/if_ether.h>
  28. #endif
  29.  
  30. #include <stdio.h>
  31. #include <signal.h>
  32. #include <errno.h>
  33. #include <netdb.h>
  34. #include <syslog.h>
  35. #include <nlist.h>
  36.  
  37. /*
  38.  * ICMP RDP packet format
  39.  * use this rather than the definition in ip_icmp.h
  40.  */
  41. struct irdppkt {
  42.     unsigned char  icmp_type;    /* type of message */
  43.     unsigned char  icmp_code;    /* type of sub code */
  44.     unsigned short icmp_cksum;    /* ones complement cksum of struct */
  45.     unsigned char  icmp_entries;/* number of entries in report */
  46.     unsigned char  icmp_size;   /* size of each entry */
  47.     unsigned short icmp_lifetime;/* lifetime of entries in this packet */
  48.     struct addrgrp {
  49.     struct in_addr    ip;
  50.     unsigned long    priority;
  51.     } addrs[1];
  52. };
  53. #ifndef    ICMP_RDPADVERT
  54. #define    ICMP_RDPADVERT    9    /* type for RDP advertisements */
  55. #define    ICMP_RDPSOLICIT    10    /* type for RDP solicitations */
  56. #endif
  57.  
  58. #define    DEFAULT_IRDP_PRIORITY    100
  59. #define    DEFAULT_IRDP_HOLDTIME    600
  60. #define    DEFAULT_IRDP_MAXADVERTINT 600
  61. #define    DEFAULT_IRDP_MINADVERTINT (DEFAULT_IRDP_MAXADVERTINT * 3 / 4)
  62.  
  63. int hold_time = DEFAULT_IRDP_HOLDTIME;    /* tell others how often to hold */
  64. int priority = DEFAULT_IRDP_PRIORITY;    /* what priority do we advertise */
  65. int min_report_time = DEFAULT_IRDP_MINADVERTINT;/* how often to send reports */
  66. int max_report_time = DEFAULT_IRDP_MAXADVERTINT;
  67.  
  68. #define    ALARM_INTERVAL        1
  69.  
  70. #define    KERNEL        "/vmunix"
  71. #define    MEM        "/dev/kmem"
  72.  
  73. struct nlist nl[] = {
  74. #define    X_ARPTAB    0
  75.     { "_arptab" },
  76. #define    X_ARPTAB_SIZE    1
  77.     { "_arptab_size" },
  78. #define    N_RTHOST    2
  79.     { "_rthost" },
  80. #define    N_RTNET        3
  81.     { "_rtnet" },
  82. #define    N_RTHASHSIZE    4
  83.     { "_rthashsize" },
  84.     { "" },
  85. };
  86.  
  87. struct iface {
  88.     char name[IFNAMSIZ];
  89.     short flags;
  90.     struct in_addr ipaddress;
  91.     struct in_addr ipmask;
  92.     struct in_addr ipbroadcast;
  93.     struct iface *next;
  94. } *iflist;
  95.  
  96. struct neighbor {
  97.     struct in_addr ip;
  98.     unsigned short priority;
  99.     unsigned short holdtime;
  100.     struct neighbor *next;
  101. };
  102.  
  103. struct neighbor *rcvd_neighbors;
  104. struct neighbor *sent_neighbors;
  105.  
  106. struct neighbor *default_neighbor;
  107.  
  108.  
  109. int debug;                /* debugging flag */
  110. int flush;                /* flush routing table flag */
  111. int logging;                /* syslog logging flag */
  112. int metric;                /* how do we run */
  113. int query_time;                /* how often to send queries */
  114. int query;
  115. int report;
  116. int round_robin;            /* how often to cycle parallel gws */
  117. int round;
  118.  
  119. int s;
  120. struct sockaddr_in from;
  121. int fromlen;
  122. struct hostent *hp;
  123. unsigned char buf[BUFSIZ];
  124.  
  125. int timer();
  126.  
  127. /*
  128.  * main
  129.  * Perform IRDP processing depending on what we were told
  130.  */
  131.  
  132. main (argc, argv)
  133.     int argc;
  134.     char *argv;
  135. {
  136.     int c, on = 1;
  137.     struct irdppkt *irdp;
  138.     struct addrgrp ag;
  139.     struct in_addr bip;
  140.     struct protoent *proto;
  141.     int oldmask;
  142.     extern char *optarg;
  143.     extern int optind;
  144.     extern int errno;
  145.  
  146.     debug = 0;
  147.     flush = 0;
  148.     logging = 0;
  149.     metric = 1;                /* default to one hop */
  150.     priority = DEFAULT_IRDP_PRIORITY;
  151.     hold_time = DEFAULT_IRDP_HOLDTIME;
  152.     query_time = 0;
  153.     min_report_time = 0;
  154.     max_report_time = 0;
  155.     round_robin = 0;
  156.     iflist = NULL;
  157.     rcvd_neighbors = NULL;
  158.     sent_neighbors = NULL;
  159.     default_neighbor = NULL;
  160.     bip.s_addr = 0L;
  161. #ifdef LOG_DAEMON
  162.     openlog("irdpd", LOG_PID, LOG_DAEMON);
  163. #else
  164.     openlog("irdpd", LOG_PID);
  165. #endif
  166.     while ((c = getopt(argc, argv, "dfh:lm:p:q:r:t:")) != EOF)
  167.     switch (c) {
  168.     case 'd':            /* debug */
  169.         debug = 1;
  170.         break;
  171.     case 'f':            /* flush  */
  172.         flush = 1;
  173.         break;
  174.     case 'h':            /* hold time */
  175.         hold_time = atoi(optarg);
  176.         if (hold_time < 0) {
  177.         fprintf(stderr, "%s: illegal hold time value - %d",
  178.             argv[0], hold_time);
  179.         exit(1);
  180.         }
  181.         break;
  182.     case 'l':            /* logging */
  183.         logging = 1;
  184.         break;
  185.     case 'm':            /* metric */
  186.         metric = atoi(optarg);
  187.         if (metric < 0) {
  188.         fprintf(stderr, "%s: illegal metric value - %d",
  189.             argv[0], metric);
  190.         exit(1);
  191.         }
  192.         break;
  193.     case 'p':            /* priority */
  194.         priority = atoi(optarg);
  195.         if (priority < 0) {
  196.         fprintf(stderr, "%s: illegal priority value - %d",
  197.             argv[0], priority);
  198.         exit(1);
  199.         }
  200.         break;
  201.     case 'q':            /* query */
  202.         query_time = atoi(optarg);
  203.         if (query_time < 0) {
  204.         fprintf(stderr, "%s: illegal querying value - %d",
  205.             argv[0], query_time);
  206.         exit(1);
  207.         }
  208.         break;
  209.     case 'r':            /* min report */
  210.         min_report_time = atoi(optarg);
  211.         if (min_report_time < 0) {
  212.         fprintf(stderr, "%s: illegal reporting value - %d",
  213.             argv[0], min_report_time);
  214.         exit(1);
  215.         }
  216.         break;
  217.     case 'R':            /* max report */
  218.         max_report_time = atoi(optarg);
  219.         if (max_report_time < 0) {
  220.         fprintf(stderr, "%s: illegal reporting value - %d",
  221.             argv[0], max_report_time);
  222.         exit(1);
  223.         }
  224.         break;
  225.     case 't':            /* time */
  226.         round_robin = atoi(optarg);
  227.         if (round_robin < 0) {
  228.         fprintf(stderr, "%s: illegal round robin value - %d",
  229.             argv[0], round_robin);
  230.         exit(1);
  231.         }
  232.         round_robin *= 60;        /* make seconds */
  233.         break;
  234.     default:
  235.         fprintf(stderr, "%s: illegal switch -%s", argv[0], optarg);
  236.         exit(1);
  237.     }
  238.  
  239.     if (query_time != 0 && max_report_time != 0) {
  240.     fprintf(stderr, "%s: cannot report and query simultaneously.\n",
  241.         argv[0]);
  242.     exit(1);
  243.     }
  244.  
  245.     bzero(&ag, sizeof(struct addrgrp));
  246.     while (argc != optind) {
  247.     ag.ip.s_addr = inet_addr(argv[optind]);
  248.     if (ag.ip.s_addr == -1) {
  249.         hp = gethostbyname(argv[optind]);
  250.         if (hp == NULL) {
  251.         fprintf(stderr, "%s: %s: unknown host\n", argv[0],
  252.             argv[optind]);
  253.         exit(1);
  254.         }
  255.         bcopy(hp->h_addr, &ag.ip, sizeof(ag.ip));
  256.     }
  257.     enter_neighbor(&sent_neighbors, ag.ip, 0, 0);
  258.     optind++;
  259.     }
  260.  
  261.     /* seed random number generator */
  262.     srandom((int) (time(0L) & INT_MAX));
  263.  
  264.     if (query_time)
  265.       query = random() % query_time;
  266.  
  267.     if (max_report_time)
  268.       report = min_report_time +
  269.            (random() % (max_report_time - min_report_time));
  270.  
  271.     round = round_robin;
  272.  
  273.     if (metric == 0 || flush) {
  274.     nlist(KERNEL, nl);
  275.     if (nl[X_ARPTAB].n_value == 0) {
  276.         fprintf(stderr, "%s: %s: bad namelist\n", argv[0], KERNEL);
  277.         exit(1);
  278.     }
  279.     if (nl[X_ARPTAB_SIZE].n_value == 0) {
  280.         fprintf(stderr, "%s: %s: bad namelist\n", argv[0], KERNEL);
  281.         exit(1);
  282.     }
  283.     if (nl[N_RTHOST].n_value == 0) {
  284.         fprintf(stderr, "%s: %s: bad namelist\n", argv[0], KERNEL);
  285.         exit(1);
  286.     }
  287.     if (nl[N_RTNET].n_value == 0) {
  288.         fprintf(stderr, "%s: %s: bad namelist\n", argv[0], KERNEL);
  289.         exit(1);
  290.     }
  291.     if (nl[N_RTHASHSIZE].n_value == 0) {
  292.         fprintf(stderr, "%s: %s: bad namelist\n", argv[0], KERNEL);
  293.         exit(1);
  294.     }
  295.     }
  296.     if (debug)
  297.     syslog(LOG_DEBUG, "server starting");
  298.  
  299.     if (!debug) {
  300.     if (fork())
  301.         exit(0);
  302.     for (c = 0; c < getdtablesize(); c++)
  303.         (void) close(c);
  304.     (void) open("/", O_RDONLY);
  305.     (void) dup2(0, 1);
  306.     (void) dup2(0, 2);
  307.     c = open("/dev/tty", O_RDWR);
  308.     if (c >= 0) {
  309.         ioctl(c, TIOCNOTTY, (char *)0);
  310.         (void) close(c);
  311.     }
  312. #ifdef LOG_DAEMON
  313.     openlog("irdpd", LOG_PID, LOG_DAEMON);
  314. #else
  315.     openlog("irdpd", LOG_PID);
  316. #endif
  317.     }
  318.  
  319.     /*
  320.      * Get listener socket
  321.      */
  322.     if ((proto = getprotobyname("icmp")) == NULL) {
  323.     syslog(LOG_ERR, "getprotobyname: %m");
  324.     exit(1);
  325.     }
  326.     if ((s = socket(AF_INET, SOCK_RAW, proto->p_proto)) < 0) {
  327.     syslog(LOG_ERR, "socket: irdp %m");
  328.     exit(1);
  329.     }
  330.  
  331. #ifdef SO_BROADCAST
  332.     if (setsockopt(s, SOL_SOCKET, SO_BROADCAST, &on, sizeof (on)) < 0) {
  333.     syslog(LOG_ERR, "setsockopt: %m");
  334.     exit(1);
  335.     }
  336. #endif
  337.  
  338.     build_iflist();
  339.     irdp_solicit(bip);
  340.     signal(SIGALRM, timer);
  341.     timer();
  342.  
  343.     /*
  344.      * Now do the work
  345.      */
  346.  
  347.     for (;;) {
  348.     fromlen = sizeof(from);
  349.     c = recvfrom(s, buf, sizeof(buf), 0, (caddr_t)&from, &fromlen);
  350.     if (c <= 0) {
  351.         if (errno == EINTR)
  352.         continue;
  353.         syslog(LOG_ERR, "recvfrom: %m");
  354.         exit(1);
  355.     }
  356.     irdp = (struct irdppkt *)buf;
  357.  
  358.     if (irdp->icmp_type != ICMP_RDPADVERT &&
  359.         irdp->icmp_type != ICMP_RDPSOLICIT)
  360.  
  361.     if (debug) {
  362.         hp = gethostbyaddr(&from.sin_addr, sizeof(struct in_addr),
  363.         AF_INET);
  364.         syslog(LOG_DEBUG, "%s received from %s",
  365.            irdp->icmp_type == ICMP_RDPADVERT ? "ADVERT" : "SOLICIT",
  366.            hp ? hp->h_name : (char *)inet_ntoa(from.sin_addr));
  367.     }
  368.  
  369.     oldmask = sigblock(sigmask(SIGALRM));
  370.     if (irdp->icmp_type == ICMP_RDPADVERT) {
  371.         if (max_report_time == 0)    /* if we're end node */
  372.           irdp_procadvert(&from, buf);
  373.     } else {
  374.         if (max_report_time != 0)    /* if we're router */
  375.           irdp_procsolicit(&from, buf);
  376.     }
  377.         sigsetmask(oldmask);
  378.     }
  379. }
  380.  
  381. /*
  382.  * find_neighbor
  383.  * Look for a given neighbor in the list and return ptr or NULL
  384.  */
  385.  
  386. struct neighbor *find_neighbor (nt, ip)
  387.     struct neighbor **nt;
  388.     struct in_addr ip;
  389. {
  390.     struct neighbor *p;
  391.  
  392.     for (p = *nt; p != NULL; p = p->next)
  393.     if (p->ip.s_addr == ip.s_addr)
  394.         break;
  395.     return(p);
  396. }
  397.  
  398. /*
  399.  * enter_neighbor
  400.  * Enter a new neighbor into the table in priority order
  401.  */
  402.  
  403. enter_neighbor (nt, ip, priority, holdtime)
  404.     struct neighbor **nt;
  405.     struct in_addr ip;
  406.     int priority, holdtime;
  407. {
  408.     struct neighbor *p, *pp, *newp;
  409.  
  410.     newp = (struct neighbor *)malloc(sizeof(struct neighbor));
  411.     if (newp == NULL)
  412.     return;
  413.  
  414.     newp->ip = ip;
  415.     newp->priority = priority;
  416.     newp->holdtime = holdtime;
  417.     newp->next = NULL;
  418.     for (p = pp = *nt; p != NULL; pp = p, p = p->next)
  419.     if (newp->priority > p->priority)
  420.         break;
  421.     if (p == NULL) {
  422.     if (*nt == NULL)
  423.         *nt = newp;
  424.     else
  425.         pp->next = newp;
  426.     } else if (p == pp) {
  427.     newp->next = *nt;
  428.     *nt = newp;
  429.     } else {
  430.     pp->next = newp;
  431.     newp->next = p;
  432.     }
  433. }
  434.  
  435. /*
  436.  * delete_neighbor
  437.  * Remove neighbor from the list
  438.  */
  439.  
  440. delete_neighbor (nt, dp)
  441.     struct neighbor **nt;
  442.     struct neighbor *dp;
  443. {
  444.     struct neighbor *p, *pp;
  445.  
  446.     for (p = pp = *nt; p != NULL; pp = p, p = p->next)
  447.     if (p == dp)
  448.         break;
  449.     if (p == pp)
  450.     *nt = p->next;
  451.     else
  452.     pp->next = p->next;
  453.     free(p);
  454.  
  455. }
  456.  
  457. /*
  458.  * robin_neighbor
  459.  * Perform round robin on received neighbors of equal priority
  460.  */
  461.  
  462. robin_neighbor ()
  463. {
  464.     struct neighbor *p, *pp;
  465.  
  466.     /*
  467.      * Find where next lower priorty starts
  468.      */
  469.     for (p = pp = rcvd_neighbors; p != NULL; p = p->next)
  470.     if (default_neighbor->priority > p->priority)
  471.         break;
  472.     /*
  473.      * If there is only a single entry, then don't bother
  474.      */
  475.     if (default_neighbor == pp)
  476.     return;
  477.  
  478.     /*
  479.      * Splice old one at end of equal priority list
  480.      */
  481.     rcvd_neighbors = default_neighbor->next;
  482.     pp->next = default_neighbor;
  483.     default_neighbor->next = p;
  484.     update_routes();
  485. }
  486.  
  487. /*
  488.  * irdp_procadvert
  489.  * handle processing of IRDP advertisements
  490.  */
  491.  
  492. irdp_procadvert (from, irdp)
  493.     struct sockaddr_in *from;
  494.     struct irdppkt *irdp;
  495. {
  496.     struct neighbor *p;
  497.     struct addrgrp *a;
  498.  
  499.     a = irdp->addrs;
  500.     while (irdp->icmp_entries-- > 0) {
  501.     if (valid_address(a->ip)) {
  502.         p = find_neighbor(&sent_neighbors, a->ip);
  503.         if (p != NULL)
  504.         p->holdtime = ntohs(irdp->icmp_lifetime);
  505.         p = find_neighbor(&rcvd_neighbors, a->ip);
  506.         if (p == NULL || p->priority != ntohs(a->priority)) {
  507.         if (p != NULL) {
  508.             if (flush)
  509.             flush_routes(p->ip);
  510.             delete_neighbor(&rcvd_neighbors, p);
  511.         }
  512.         enter_neighbor(&rcvd_neighbors, a->ip,
  513.                    ntohs(a->priority), ntohs(irdp->icmp_lifetime));
  514.         update_routes();
  515.         round = round_robin;        /* restart timer */
  516.         } else
  517.         p->holdtime = ntohs(irdp->icmp_lifetime);
  518.     } else if (debug)
  519.         syslog(LOG_DEBUG, "invalid IP address: %s",
  520.         inet_ntoa(a->ip));
  521.     a++;
  522.     }
  523. }
  524.  
  525. /*
  526.  * irdp_procsolicit
  527.  * Process a solicitation send out irdp packets on all ports
  528.  */
  529.  
  530. irdp_procsolicit (from, irdp)
  531.     struct sockaddr_in *from;
  532.     struct irdppkt *irdp;
  533. {
  534. }
  535.  
  536. /*
  537.  * timer
  538.  * Wake up once in a while and process running timers, etc.
  539.  */
  540.  
  541. timer ()
  542. {
  543.     struct neighbor *p, *dp;
  544.     struct in_addr bip;
  545.  
  546.     bip.s_addr = 0L;
  547.     if (max_report_time != 0) {
  548.     if (report <= 0) {
  549.         irdp_advert(bip);
  550.         report = min_report_time +
  551.           (random() % (max_report_time - min_report_time));
  552.     } else
  553.         report -= ALARM_INTERVAL;
  554.     } else {
  555.     if (query_time != 0) {
  556.         query -= ALARM_INTERVAL;
  557.         if (query <= 0) {
  558.         for (p = sent_neighbors; p != NULL; p = p->next)
  559.             irdp_solicit(p->ip);
  560.         query = query_time;
  561.         }
  562.     }
  563.     for (p = rcvd_neighbors; p != NULL; ) {
  564.         dp = p;
  565.         p = p->next;
  566.         dp->holdtime -= ALARM_INTERVAL;
  567.         if (dp->holdtime <= 0) {
  568.         if (flush)
  569.             flush_routes(dp->ip);
  570.         delete_neighbor(&rcvd_neighbors, dp);
  571.         update_routes();
  572.         round = round_robin;        /* restart timer */
  573.         }
  574.     }
  575.     }
  576.     if (round_robin != 0) {
  577.     round -= ALARM_INTERVAL;
  578.     if (round <= 0) {
  579.         if (default_neighbor != NULL)
  580.         robin_neighbor();
  581.         round = round_robin;
  582.     }
  583.     }
  584.     alarm(ALARM_INTERVAL);
  585. }
  586.  
  587. /*
  588.  * irdp_solicit
  589.  * Send a IRDP solictation - if IP = 0, send to all broadcast interfaces
  590.  */
  591.  
  592. irdp_solicit (ip)
  593.     struct in_addr ip;
  594. {
  595.     struct irdppkt irdp;
  596.     struct sockaddr_in sin;
  597.     struct iface *ifp;
  598.     struct neighbor *p;
  599.  
  600.     bzero(&irdp, sizeof(irdp));
  601.     irdp.icmp_type = ICMP_RDPSOLICIT;
  602.     irdp.icmp_cksum = in_cksum(irdp, sizeof(irdp)-sizeof(struct addrgrp));
  603.  
  604.     bzero(&sin, sizeof(sin));
  605.     sin.sin_family = AF_INET;
  606.     sin.sin_addr = ip;
  607.     if (ip.s_addr == 0L) {
  608.     for (ifp = iflist; ifp != NULL; ifp = ifp->next) {
  609.         if ((ifp->flags & IFF_BROADCAST) == 0)
  610.         continue;
  611.         sin.sin_addr = ifp->ipbroadcast;
  612.         (void) sendto(s, &irdp, sizeof(irdp) - sizeof(struct addrgrp), 0,
  613.         &sin, sizeof(sin));
  614.     }
  615.     for (p = sent_neighbors; p != NULL; p = p->next)
  616.         irdp_solicit(p->ip);
  617.     } else
  618.     (void) sendto(s, &irdp, sizeof(irdp) - sizeof(struct addrgrp), 0,
  619.         &sin, sizeof(sin));
  620. }
  621.  
  622. /*
  623.  * irdp_advert
  624.  * Send a IRDP REPORT message
  625.  */
  626.  
  627. irdp_advert (ip)
  628.     struct in_addr ip;
  629. {
  630. }
  631.  
  632. /*
  633.  * build_iflist
  634.  * Build a list of interfaces and accompaning information
  635.  */
  636.  
  637. build_iflist ()
  638. {
  639.     int n;
  640.     char ifbuf[BUFSIZ];
  641.     struct ifconf ifc;
  642.     struct ifreq *ifr, ifreq;
  643.     struct iface *ifp;
  644.     struct sockaddr_in *sa;
  645.     short flags;
  646.  
  647.     ifc.ifc_len = sizeof(ifbuf);
  648.     ifc.ifc_buf = ifbuf;
  649.     if (ioctl(s, SIOCGIFCONF, &ifc) < 0) {
  650.     syslog(LOG_ERR, "ioctl(IFCONF): %m");
  651.     exit(1);
  652.     }
  653.     ifr = ifc.ifc_req;
  654.     for (n = ifc.ifc_len / sizeof(struct ifreq); n > 0; n--, ifr++) {
  655.     /*
  656.      * Ignore the loopback interface
  657.      */
  658.     if (strncmp(ifr->ifr_name, "lo", 2) == 0)
  659.         continue;
  660.     /*
  661.      * Ignore all interfaces which aren't running
  662.      */
  663.     strncpy(ifreq.ifr_name, ifr->ifr_name, sizeof(ifreq.ifr_name));
  664.     if (ioctl(s, SIOCGIFFLAGS, &ifreq) < 0)
  665.         continue;
  666.     else
  667.         flags = ifreq.ifr_flags;
  668.     if ((flags & IFF_RUNNING) == 0)
  669.         continue;
  670.     sa = (struct sockaddr_in *)&ifr->ifr_addr;
  671.     /*
  672.      * Ignore non-internet family and 0.0.0.0
  673.      */
  674.     if (sa->sin_family != AF_INET || sa->sin_addr.s_addr == 0L)
  675.         continue;
  676.     ifp = (struct iface *)malloc(sizeof(struct iface));
  677.     if (ifp == NULL)
  678.         break;
  679.     bzero(ifp, sizeof(struct iface));
  680.     strncpy(ifp->name, ifr->ifr_name, sizeof(ifp->name));
  681.     ifp->ipaddress = sa->sin_addr;
  682.     ifp->flags = flags;
  683.     strncpy(ifreq.ifr_name, ifp->name, sizeof(ifp->name));
  684.     if (ioctl(s, SIOCGIFNETMASK, &ifreq) >= 0) {
  685.         sa = (struct sockaddr_in *)&ifreq.ifr_addr;
  686.         ifp->ipmask = sa->sin_addr;
  687.     }
  688.     if (ifp->flags & IFF_BROADCAST) {
  689.         strncpy(ifreq.ifr_name, ifp->name, sizeof(ifp->name));
  690.         if (ioctl(s, SIOCGIFBRDADDR, &ifreq) >= 0) {
  691.         sa = (struct sockaddr_in *)&ifreq.ifr_addr;
  692.         ifp->ipbroadcast = sa->sin_addr;
  693.         }
  694.     }
  695.     if (iflist == NULL)
  696.         iflist = ifp;
  697.     else {
  698.         ifp->next = iflist;
  699.         iflist = ifp;
  700.     }
  701.     }
  702. }
  703.  
  704. /*
  705.  * valid_address
  706.  * Determine if give IP address is something we grok.
  707.  */
  708.  
  709. valid_address (ip)
  710.     struct in_addr ip;
  711. {
  712.     struct iface *ifp;
  713.  
  714.     for (ifp = iflist; ifp != NULL; ifp = ifp->next) {
  715.     if ((ip.s_addr & ifp->ipmask.s_addr) ==
  716.         (ifp->ipaddress.s_addr & ifp->ipmask.s_addr))
  717.         return(1);
  718.     }
  719.     return(0);
  720. }
  721.  
  722. /*
  723.  * update_routes
  724.  * Update default route if necessary when something changes
  725.  */
  726.  
  727. update_routes ()
  728. {
  729.     struct rtentry rt;
  730.     struct sockaddr_in *sa;
  731.     struct in_addr inet_makeaddr();
  732.  
  733.     if (default_neighbor == rcvd_neighbors)
  734.     return;
  735.  
  736.     bzero(&rt, sizeof(rt));
  737.     rt.rt_flags = RTF_UP;
  738.     if (metric > 0)
  739.     rt.rt_flags |= RTF_GATEWAY;
  740.     sa = (struct sockaddr_in *)&rt.rt_dst;
  741.     sa->sin_family = AF_INET;
  742.     sa->sin_addr = inet_makeaddr(0, INADDR_ANY);
  743.     sa = (struct sockaddr_in *)&rt.rt_gateway;
  744.     sa->sin_family = AF_INET;
  745.     if (default_neighbor != NULL) {
  746.     sa->sin_addr = default_neighbor->ip;
  747.     if (metric == 0)
  748.         flush_arp();
  749.     if (logging)
  750.         syslog(LOG_NOTICE, "deleting old default: %s",
  751.         inet_ntoa(sa->sin_addr));
  752.     if (!debug)
  753.         (void) ioctl(s, SIOCDELRT, &rt);
  754.     }
  755.     default_neighbor = rcvd_neighbors;
  756.     if (default_neighbor == NULL)
  757.     return;
  758.     sa->sin_addr = default_neighbor->ip;
  759.     if (logging)
  760.     syslog(LOG_NOTICE, "adding new default: %s",
  761.         inet_ntoa(sa->sin_addr));
  762.     if (!debug)
  763.     (void) ioctl(s, SIOCADDRT, &rt);
  764. }
  765.  
  766. /*
  767.  * flush_arp
  768.  * Flush the ARP tables. Used when we delete a default route and metric
  769.  * is zero.
  770.  */
  771.  
  772. flush_arp ()
  773. {
  774.     int size, fd;
  775.     int arptab_size;
  776.     struct arptab *atp;
  777.     struct arptab *at;
  778.     struct arpreq ar;
  779.     struct sockaddr_in *sa;
  780.  
  781.     if (logging)
  782.     syslog(LOG_NOTICE, "flushing ARP tables");
  783.     if (debug)
  784.     return;
  785.     fd = open(MEM, O_RDONLY);
  786.     if (fd < 0) {
  787.     syslog(LOG_ERR,"%s: cannot open", MEM);
  788.     exit(1);
  789.     }
  790.  
  791.     if (lseek(fd, (long)nl[X_ARPTAB_SIZE].n_value, 0) == -1 ||
  792.     read(fd, &arptab_size, sizeof(arptab_size)) != sizeof(arptab_size) ||
  793.     arptab_size < 0 || arptab_size > 10000) {
  794.     syslog(LOG_ERR, "bad ARP namelist");
  795.     exit(1);
  796.     }
  797.     size = arptab_size * sizeof(struct arptab);
  798.     atp = (struct arptab *)malloc(size);
  799.     at = atp;
  800.     if (at == NULL) {
  801.     close(fd);
  802.     return;
  803.     }
  804.  
  805.     if (lseek(fd, (long)nl[X_ARPTAB].n_value, 0) == -1 ||
  806.     read(fd, (char *)at, size) != size) {
  807.     syslog(LOG_ERR, "error reading ARP table %m");
  808.     exit(1);
  809.     }
  810.     bzero(&ar, sizeof(ar));
  811.     sa = (struct sockaddr_in *)&ar.arp_pa;
  812.     sa->sin_family = AF_INET;
  813.     for ( ; arptab_size-- > 0; at++) {
  814. #ifndef pyr
  815.     if (at->at_iaddr.s_addr == 0 || at->at_flags == 0)
  816. #else
  817.     struct sockaddr_in sin;
  818.  
  819.     bcopy(&at->at_addr, &sin, sizeof(struct sockaddr_in));
  820.     if (sin.sin_addr.s_addr == 0 || at->at_flags == 0)
  821. #endif
  822.         continue;
  823.     if (at->at_flags & ATF_PERM)
  824.         continue;
  825. #ifndef pyr
  826.     sa->sin_addr = at->at_iaddr;
  827. #else
  828.     sa->sin_addr = sin.sin_addr;
  829. #endif
  830.     (void) ioctl(s, SIOCDARP, &ar);
  831.     }
  832.     close(fd);
  833.     free(atp);
  834. }
  835.  
  836. /*
  837.  * flush_routes
  838.  * Flush the routing table. We do this when asked.
  839.  */
  840.  
  841. flush_routes (ip)
  842.     struct in_addr ip;
  843. {
  844.     struct in_addr gwin, dstin;
  845.     struct mbuf mb;
  846.     register struct rtentry *rt;
  847.     register struct mbuf *mbp;
  848.     struct mbuf **routehash;
  849.     int rthashsize, i, doinghost = 1, fd;
  850.  
  851.     fd = open(MEM, O_RDONLY);
  852.     if (fd < 0) {
  853.     syslog(LOG_ERR,"%s: cannot open", MEM);
  854.     exit(1);
  855.     }
  856.  
  857.     if (lseek(fd, nl[N_RTHASHSIZE].n_value, 0) == -1 ||
  858.     read(fd, &rthashsize, sizeof (rthashsize)) != sizeof(rthashsize)) {
  859.     syslog(LOG_ERR, "bad ROUTE namelist");
  860.     exit(1);
  861.     }
  862.     if (logging)
  863.     syslog(LOG_NOTICE, "flushing routes via %s", inet_ntoa(ip));
  864.     routehash = (struct mbuf **)malloc(rthashsize*sizeof (struct mbuf *));
  865.     if (routehash == NULL) {
  866.     close(fd);
  867.     return;
  868.     }
  869.     if (lseek(fd, nl[N_RTHOST].n_value, 0) == -1 ||
  870.     read(fd, routehash, rthashsize*sizeof (struct mbuf *)) !=
  871.     rthashsize*sizeof(struct mbuf *)) {
  872.     syslog(LOG_ERR, "error reading ROUTE table %m");
  873.     exit(1);
  874.     }
  875. again:
  876.     for (i = 0; i < rthashsize; i++) {
  877.     if (routehash[i] == 0)
  878.         continue;
  879.     mbp = routehash[i];
  880.         while (mbp) {
  881.         if (lseek(fd, mbp, 0) == -1 ||
  882.             read(fd, &mb, sizeof (mb)) != sizeof(mb))
  883.             goto done;
  884.         rt = mtod(&mb, struct rtentry *);
  885.         if ((rt->rt_flags & RTF_GATEWAY) &&
  886.             rt->rt_gateway.sa_family == AF_INET) {
  887.             gwin = ((struct sockaddr_in *)&rt->rt_gateway)->sin_addr;
  888.             dstin = ((struct sockaddr_in *)&rt->rt_dst)->sin_addr;
  889.             /*
  890.              * Flush all routes through this device except
  891.              * default which is done later.
  892.              */
  893.             if (gwin.s_addr == ip.s_addr && dstin.s_addr != 0L) {
  894.             if (logging) {
  895.                 syslog(LOG_NOTICE, "flushing route %s",
  896.                 inet_ntoa(dstin));
  897.             }
  898.             if (!debug)
  899.                 (void) ioctl(s, SIOCDELRT, (caddr_t)rt);
  900.             }
  901.         }
  902.         mbp = mb.m_next;
  903.         }
  904.     }
  905.     if (doinghost) {
  906.     if (lseek(fd, nl[N_RTNET].n_value, 0) == -1 ||
  907.         read(fd, routehash, rthashsize*sizeof (struct mbuf *)) !=
  908.         rthashsize*sizeof(struct mbuf *))
  909.         goto done;
  910.     doinghost = 0;
  911.     goto again;
  912.     }
  913. done:
  914.     free(routehash);
  915.     close(fd);
  916. }
  917.  
  918. /*
  919.  * Copyright (c) 1987 Regents of the University of California.
  920.  * All rights reserved.
  921.  *
  922.  * Redistribution and use in source and binary forms are permitted
  923.  * provided that the above copyright notice and this paragraph are
  924.  * duplicated in all such forms and that any documentation,
  925.  * advertising materials, and other materials related to such
  926.  * distribution and use acknowledge that the software was developed
  927.  * by the University of California, Berkeley.  The name of the
  928.  * University may not be used to endorse or promote products derived
  929.  * from this software without specific prior written permission.
  930.  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  931.  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  932.  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  933.  */
  934. /*
  935.  *            I N _ C K S U M
  936.  *
  937.  * Checksum routine for Internet Protocol family headers (C Version)
  938.  *
  939.  */
  940. int
  941. in_cksum(addr, len)
  942. unsigned short *addr;
  943. int len;
  944. {
  945.     register int nleft = len;
  946.     register u_short *w = addr;
  947.     register u_short answer;
  948.     register int sum = 0;
  949.     u_short odd_byte = 0;
  950.  
  951.     /*
  952.      *  Our algorithm is simple, using a 32 bit accumulator (sum),
  953.      *  we add sequential 16 bit words to it, and at the end, fold
  954.      *  back all the carry bits from the top 16 bits into the lower
  955.      *  16 bits.
  956.      */
  957.     while( nleft > 1 )  {
  958.         sum += *w++;
  959.         nleft -= 2;
  960.     }
  961.  
  962.     /* mop up an odd byte, if necessary */
  963.     if( nleft == 1 ) {
  964.         *(u_char *)(&odd_byte) = *(u_char *)w;
  965.         sum += odd_byte;
  966.     }
  967.  
  968.     /*
  969.      * add back carry outs from top 16 bits to low 16 bits
  970.      */
  971.     sum = (sum >> 16) + (sum & 0xffff);    /* add hi 16 to low 16 */
  972.     sum += (sum >> 16);            /* add carry */
  973.     answer = ~sum;                /* truncate to 16 bits */
  974.     return (answer);
  975. }
  976.